#
# Copyright 2009 Red Hat, Inc. and/or its affiliates.
#
# Licensed to you under the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  See the files README and
# LICENSE_GPL_v2 which accompany this distribution.
#

import basicVdsTest
import os, re
import sanity_mate as sm
import unittest as ut
from confUtils import mergeTemplates
import qaDB as qadb

#------------------------------------------------------------------------------
class StoragePoolSanityTest(basicVdsTest.BasicVDSTest):

    @classmethod
    def getConfigTemplate(cls):
        return mergeTemplates([sm.__commonTemplate__, sm.__nfsTemplate__,
            sm.__iscsiTemplate__, sm.__fcpTemplate__])

    def setUp(self):
        """
        Common setup
        """

        cfg = self.cfg['common']
        self.debug = int(cfg['testDebug'])
        self.dcNamePref = cfg['dcNamePref']
        self.vds1 = cfg['vds1']
        self.logFile = "/tmp/sanity.log"
        self.storageTypeName = cfg['storageType']
        self.storageType = int(sm.storageTypes_e[self.storageTypeName])
        self.iso = self.cfg['iso']

        self.storageParams = {}
        self.storageParams[self.storageType] = []
        for section in self.cfg.keys():
            if re.match(self.storageTypeName, section, re.I):
                conn = {}
                for opt in self.cfg[section]:
                    conn[opt] = self.cfg[section][opt]
                self.storageParams[self.storageType].append(conn)

        basicVdsTest.BasicVDSTest.setUp(self)
        self.common = sm.VDSClient_accessory(self.logFile)
        self.common.setUp(self.vds1)
        self.qadb = qadb.DBcommunicator(self.logFile)
        self.testStatus = True

        if self.debug == 2:
            import pdb
            pdb.set_trace()

        isQaDB = int(cfg['qadb'])
        if isQaDB == 1:
            qaSetupName = cfg['qaSetup']
            buildName = cfg['buildName']
            vdsCap = self.common.getVdsCap()
            self.qadb.initDBParams(self.storageTypeName, buildName,
                vdsCap['software_version'], vdsCap['software_revision'],
                qaSetupName)

#        if os.path.exists(self.logFile):
#            os.unlink(self.logFile)
#            os.mknod(self.logFile)

    @classmethod
    def tests(cls):
        return ([
                "CreateStoragePoolWithDomainList",
                "CreateStoragePoolWithOneDomain",
                "ChangeStorageDomainStatus",
                "SwitchMasterDomain",
#                "ConnectStoragePool"
                ])

    def assertCallAndLog(self, msg, method, *args):
        fun = getattr(self.common, method)
        rc = fun(*args)
        self.__log__(msg, rc)
        self.assertTrue(rc, "ERROR in: %s" % msg)

    def tearDown(self):
        self.assertCallAndLog("DestroyStoragePool", "removeSP", self.storageType,
        self._createSPName(), self.storageParams[self.storageType], self.iso)
        self.qadb.testEnd(self.testStatus)
        basicVdsTest.BasicVDSTest.tearDown(self)

    def __log__(self, msg, rc = True, dbMsg = 'info'):
        sm.writeLog(msg, self.logFile, self.debug)
        if not rc:
            self.testStatus = False
        if dbMsg == 'start':
            self.qadb.testStart(msg)
        elif dbMsg == 'info':
            self.qadb.testPrintInfo(rc, msg)

    def _createSPName(self):
        return self.dcNamePref + self.storageTypeName

    def createSP_method_1(self):
        self.__log__("createStoragePoolWithListOfDomains_" + self.storageTypeName, dbMsg = 'start')
        spName = self._createSPName()

        self.assertCallAndLog("CreatStoragePool", "createSP", self.storageType,
            spName, self.storageParams[self.storageType], self.iso)
        self.assertCallAndLog("CheckStoragePoolinfo", "checkPoolInfo", spName)
        return True

    def createSP_method_2(self):
        self.__log__("createStoragePoolWithOneDomain_" + self.storageTypeName, dbMsg = 'start')
        spName = self._createSPName()

        newStParams = []
        newStParams.append(self.storageParams[self.storageType][0])
        self.assertCallAndLog("CreatStoragePool", "createSP", self.storageType,
            spName, newStParams)

        spUuid = self.common.getPoolUuidByName(spName)
        self.failIf(not spUuid, "ERROR: getPoolUuidByName")
        self.storageParams[self.storageType].remove(self.storageParams[self.storageType][0])
        ind = 2
        sdNamePref = self.storageTypeName + '_domain_'
        for st in self.storageParams[self.storageType]:
            sdName = sdNamePref + str(ind)
            self.assertCallAndLog("AddStorageDomainsToPool", "addDomainToStoragePool",
                spUuid, self.storageType, sm.DATA_DOMAIN, sdName, st)
            ind += 1

        self.assertCallAndLog("CheckStoragePoolinfo", "checkPoolInfo", spName)
        self.iso = None #ugly
        return True

    def changeSDStatus(self):
        self.__log__("changeStorageDomainStatus_" + self.storageTypeName, dbMsg = 'start')
        spName = self._createSPName()

        self.assertCallAndLog("CreatStoragePool", "createSP", self.storageType,
            spName, self.storageParams[self.storageType], self.iso)

        spUuid = self.common.getPoolUuidByName(spName)
        sdList = self.common.getPoolDomains(spUuid)
        sdMaster = self.common.getPoolMasterDomain(spUuid)
        sdIso = self.common.getPoolIsoDomain(spUuid)
        self.failIf((not spUuid or not sdList or not sdMaster or not sdIso),
            "ERROR getting storage pool %s domains!" % str(spUuid))
        testSd = False
        for sdUuid in sdList:
            if sdUuid != sdMaster and sdUuid != sdIso:
                testSd = sdUuid
                break
        self.failIf(not testSd, "ERROR: must have at least one regular(not master) storage domain!")

        self.assertCallAndLog("DeactivateRegularDataSDandCheckStatus",
            "changeDomainStatus", testSd, spUuid, sm.INACTIVE)
        self.assertCallAndLog("DetachDataSDandCheckStatus",
            "changeDomainStatus", testSd, spUuid, sm.UNATTACHED)
        self.assertCallAndLog("AttachDataSDandCheckStatus",
            "changeDomainStatus", testSd, spUuid, sm.ATTACHED)
        self.assertCallAndLog("ActivateDataSDandCheckStatus",
            "changeDomainStatus", testSd, spUuid, sm.ACTIVE)
        #try to detach an active SD
        self.assertRaises(AssertionError, self.common.changeDomainStatus, testSd, spUuid, sm.UNATTACHED)
        self.__log__("Try to detach an active SD (failure expected)")
        return True

    def switchMasterSD(self):
        self.__log__("switchMasterStorageDomain_" + self.storageTypeName, dbMsg = 'start')
        spName = self._createSPName()

        self.assertCallAndLog("CreatStoragePool", "createSP", self.storageType,
            spName, self.storageParams[self.storageType], self.iso)

        spUuid = self.common.getPoolUuidByName(spName)
        sdList = self.common.getPoolDomains(spUuid)
        sdMaster = self.common.getPoolMasterDomain(spUuid)
        sdIso = self.common.getPoolIsoDomain(spUuid)
        self.failIf((not spUuid or not sdList or not sdMaster or not sdIso),
            "ERROR getting storage pool %s domains!" % str(spUuid))

        testSd = False
        for sdUuid in sdList:
            if sdUuid != sdMaster and sdUuid != sdIso:
                testSd = sdUuid
                break
        self.failIf(not testSd, "ERROR: must have at least one regular(not master) storage domain!")

        #switch master domain
        newMasterSd = testSd
        self.assertCallAndLog("MasterDomainMigration", "changeDomainStatus",
            sdMaster, spUuid, sm.INACTIVE, newMasterSd)

        oldMasterSd = sdMaster
        sdMaster = newMasterSd
        self.assertCallAndLog("DetachExMasterDomain", "changeDomainStatus",
            oldMasterSd, spUuid, sm.UNATTACHED, newMasterSd)
        #add SD back to SP
        self.assertCallAndLog("AttachExMasterDomain", "changeDomainStatus",
            oldMasterSd, spUuid, sm.ATTACHED)
        self.assertCallAndLog("ActivateExMasterDomain", "changeDomainStatus",
            oldMasterSd, spUuid, sm.ACTIVE)

        #try to set ISO domain as Master
        self.assertRaises(AssertionError, self.common.changeDomainStatus, oldMasterSd, spUuid, sm.UNATTACHED, newMasterSd)
        self.__log__("Try to set ISO domain as Master (failure expected)")
        return True

    def connectSP(self):
        self.__log__("connectStoragePool " + self.storageTypeName)
        return True

    def CreateStoragePoolWithDomainList(self):
        self.assertTrue(self.createSP_method_1())

    def CreateStoragePoolWithOneDomain(self):
        self.assertTrue(self.createSP_method_2())

    def ChangeStorageDomainStatus(self):
        self.assertTrue(self.changeSDStatus())

    def SwitchMasterDomain(self):
        self.assertTrue(self.switchMasterSD())

    def ConnectStoragePool(self):
        self.assertTrue(self.connectSP())

#------------------------------------------------------------------------------
def suite():

    tests = {
        StoragePoolSanityTest : StoragePoolSanityTest.tests()
    }
    resSuite = ut.TestSuite()
    for testcase, methods in tests.iteritems():
        resSuite.addTests(map(testcase, methods))
    return resSuite

validateConfig = lambda cfg : basicVdsTest.validateSuiteConfig(suite(), cfg)
